package cn.iocoder.yudao.module.digital.service.cardkeyorder;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.digital.dal.dataobject.cardkeyorder.CardkeyOrderCardSecretDO;
import cn.iocoder.yudao.module.digital.dal.dataobject.cardkeyorder.CardkeyOrderDO;
import cn.iocoder.yudao.module.digital.dal.dataobject.cardkeyorder.CardkeyOrderProductDO;
import cn.iocoder.yudao.module.digital.dal.mysql.cardkeyorder.CardkeyOrderMapper;
import cn.iocoder.yudao.module.digital.enums.cardkeysecret.CardKeySourceEnum;
import cn.iocoder.yudao.module.digital.service.cardchannel.model.common.CdkGenCardReq;
import cn.iocoder.yudao.module.digital.service.cardchannel.model.common.CdkOrderStatusEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.digital.enums.ErrorCodeConstants.CARDKEY_ORDER_NOT_EXISTS;

/**
 * 卡密订单 Service 实现类
 *
 * @author 超管
 */
@Service
@Validated
public class CardkeyOrderServiceImpl implements CardkeyOrderService {

    @Resource
    private CardkeyOrderMapper cardkeyOrderMapper;

//    private void validateCardkeyOrderExists(String id) {
//        if (cardkeyOrderMapper.selectById(id) == null) {
//            throw exception(CARDKEY_ORDER_NOT_EXISTS);
//        }
//    }


    @Override
    public CardkeyOrderDO getCardKeyOrder(String id) {
        final CardkeyOrderDO cardkeyOrderDO = cardkeyOrderMapper.selectById(id);
        if (cardkeyOrderDO == null) {
            throw exception(CARDKEY_ORDER_NOT_EXISTS);
        }
        return cardkeyOrderDO;
    }

    @Override
    public CardkeyOrderDO getCardKeyOrderNoCheck(String id) {
        return cardkeyOrderMapper.selectById(id);
    }

    @Override
    public CardkeyOrderDO getCardKeyOrderByChannelCardOrderId(CardKeySourceEnum source, String channelCardOrderId) {
        final LambdaQueryWrapper<CardkeyOrderDO> wrapper = Wrappers.lambdaQuery();
        wrapper.notIn(CardkeyOrderDO::getSource, source.getValue());
        wrapper.lt(CardkeyOrderDO::getChannelOrderId, channelCardOrderId);
        CardkeyOrderDO cardkeyOrderDO = cardkeyOrderMapper.selectOne(wrapper);
        if (cardkeyOrderDO == null) {
            throw exception(CARDKEY_ORDER_NOT_EXISTS);
        }
        return cardkeyOrderDO;
    }

    @Override
    public String createCardKeyOrder(CardKeySourceEnum source, String cardOrderId, List<CdkGenCardReq.Product> products) {
        final CardkeyOrderDO order = new CardkeyOrderDO();
        order.setId(cardOrderId);
        order.setSource(source.getValue());
        order.setOrderStatus(CdkOrderStatusEnum.SUBMIT_INIT.getValue());
        final List<CardkeyOrderProductDO> productDOs = products.stream().map(product -> toCardkeyOrderProductDO(product)).collect(Collectors.toList());
        order.setProducts(productDOs);
        final AtomicInteger productQuantity = new AtomicInteger();
        productDOs.forEach(v -> {
            productQuantity.addAndGet(v.getQuantity());
        });
        order.setProductQuantity(productQuantity.get());
        cardkeyOrderMapper.insert(order);
        return cardOrderId;
    }

    private CardkeyOrderProductDO toCardkeyOrderProductDO(CdkGenCardReq.Product product) {
        final CardkeyOrderProductDO productDO = new CardkeyOrderProductDO();
        productDO.setProductNo(product.getProductNo());
        productDO.setCurrencyCode(product.getCurrencyCode());
        productDO.setBuyDenomination(product.getBuyDenomination());
        productDO.setQuantity(product.getQuantity());
        return productDO;
    }

    @Override
    public void updateCardKeyOrder(String cardOrderId, String channelOrderId, String channelInnerOrderId,
                                   CdkOrderStatusEnum orderStatus, String errorMsg,
                                   List<CardkeyOrderCardSecretDO> cards) {
        errorMsg = getErrorMsg(errorMsg);

        final CardkeyOrderDO order = new CardkeyOrderDO()
                .setId(cardOrderId)
                .setChannelOrderId(channelOrderId)
                .setChannelInnerOrderId(channelInnerOrderId)
                .setOrderStatus(orderStatus.getValue())
                .setErrorMsg(errorMsg)
                .setCardQuantity(CollUtil.isNotEmpty(cards) ? cards.size() : 0)
                .setCards(cards);
        cardkeyOrderMapper.updateById(order);
    }

    @Override
    public void updateCardKeyOrderFailOrException(String cardOrderId, String channelOrderId, String channelInnerOrderId,
                                                  CdkOrderStatusEnum orderStatus, String errorMsg) {
        errorMsg = getErrorMsg(errorMsg);

        final CardkeyOrderDO order = new CardkeyOrderDO()
                .setChannelOrderId(channelOrderId)
                .setChannelInnerOrderId(channelInnerOrderId)
                .setOrderStatus(orderStatus.getValue())
                .setErrorMsg(errorMsg);

        final LambdaQueryWrapper<CardkeyOrderDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CardkeyOrderDO::getId, cardOrderId);
        wrapper.notIn(CardkeyOrderDO::getOrderStatus, Arrays.asList(
                CdkOrderStatusEnum.CARD_SUCCESS.getValue(),
                CdkOrderStatusEnum.CARD_PARTIAL_SUCCESS.getValue(),
                CdkOrderStatusEnum.CARD_FAILURE.getValue()
        ));

        cardkeyOrderMapper.update(order, wrapper);
    }

    private static String getErrorMsg(String errorMsg) {
        if (errorMsg == null) {
            errorMsg = "";
        }
        if (errorMsg.length() > 1024) {
            errorMsg = errorMsg.substring(0, 1024);
        }
        return errorMsg;
    }

    @Override
    public List<CardkeyOrderDO> getTimeoutCardKeyOrder(Duration timeoutDuration) {
        final LambdaQueryWrapper<CardkeyOrderDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CardkeyOrderDO::getOrderStatus, CdkOrderStatusEnum.CARD_PROCESSING.getValue());
        final LocalDateTime beforeTimeout = LocalDateTime.now().minus(timeoutDuration);
        wrapper.lt(CardkeyOrderDO::getCreateTime, beforeTimeout);
        return cardkeyOrderMapper.selectList(wrapper);
    }

    public static void main(String[] args) {
        Duration timeoutDuration = Duration.ofMinutes(60);
        final LocalDateTime beforeTimeout = LocalDateTime.now().minus(timeoutDuration);
        System.out.println(beforeTimeout);
    }

}